package applets;

import java.applet.Applet;
import java.awt.Button;
import java.awt.Color;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import wheel.KeyWheel;
import wheel.M209Wheels;
import algorithms.GetBeaufortKey;
import algorithms.Key;
import bar.Bar;
import bar.Lug;
import bar.M209Bars;

public class GetBeaufortKeyApplet extends Applet implements ActionListener {

    /**
     * serial ID
     */
    private static final long serialVersionUID = -4316982731468739714L;

    M209Wheels m209wheels = new M209Wheels();
    M209Bars m209Bars = new M209Bars();
    GetBeaufortKey getBeaufortKey = new GetBeaufortKey();

    TextField inputLine = new TextField(15);
    TextField inputLine2 = new TextField(15);

    Map<KeyWheel, List<Button>> keysButtons = new HashMap<KeyWheel, List<Button>>();
    Map<Bar, List<Button>> lugsButtons = new HashMap<Bar, List<Button>>();

    
    // TO VISUALIZE THE SETTINGS
    Color DEFAULT_BG = Color.WHITE;
    Color ACTIVE_BG = Color.PINK;
    
    // TO VIZUALIZE THE ACTIVE PARTS
    Color DEFAULT_FG = Color.BLACK;
    Color ACTIVE_FG = Color.RED;

    public GetBeaufortKeyApplet() {

	repaint();
    }

    public void init() {
	setLayout(null);
	setSize(1200, 700);

	int x = 0, y = 0;
	int marge = 5;
	int size = 20;

	// SETTING OF THE PINS

	for (KeyWheel wheel : m209wheels.getKeyWheels()) {
	    keysButtons.put(wheel, new ArrayList<Button>());

	    for (Key key : wheel.getKeys()) {
		keysButtons.get(wheel).add(new Button(key.name()));
	    }

	    x = 0;
	    for (Button button : keysButtons.get(wheel)) {
		button.setBounds(2 * marge + (size + marge) * x, 2 * marge + (size + marge) * y, size, size);
		if (wheel.getKeyPins().get(Key.charToKey(button.getLabel().charAt(0)))) {
		    button.setBackground(ACTIVE_BG);
		} else {
		    button.setBackground(DEFAULT_BG);
		}
		add(button);
		button.addActionListener(this);
		x++;
	    }
	    y++;

	}
	int y2 = y;
	x = 28;
	y = 0;

	// SETTING OF THE LUGS
	List<Lug> nums = new ArrayList<Lug>();
	nums.add(Lug.One);
	nums.add(Lug.Zero);
	nums.add(Lug.Two);
	nums.add(Lug.Three);
	nums.add(Lug.Four);
	nums.add(Lug.Five);
	nums.add(Lug.Zero2);
	nums.add(Lug.Six);

	for (Bar bar : m209Bars.getBars()) {
	    lugsButtons.put(bar, new ArrayList<Button>());

	    for (Lug lug : nums) {
		lugsButtons.get(bar).add(new Button(lug.getId()));
	    }

	    x = 28;
	    for (Button button : lugsButtons.get(bar)) {
		button.setBounds(2 * marge + (size + marge) * x, 2 * marge + (size + marge) * y, size, size);
		if (bar.getLug1().getId().equals(button.getLabel()) || bar.getLug2().getId().equals(button.getLabel())) {
		    button.setBackground(ACTIVE_BG);
		} else {
		    button.setBackground(DEFAULT_BG);
		}
		add(button);
		button.addActionListener(this);
		x++;
	    }
	    y++;

	}

	// EXTERNAL KEY
	y2++;
	y2++;

	inputLine.setBounds(2 * marge, 2 * marge + y2 * (size + marge), 200, size);
	add(inputLine);
	inputLine.addActionListener(this);
	inputLine.setText("external key e.g. PURPLE");
	y2++;

	// RESULT

	inputLine2.setBounds(2 * marge, 2 * marge + y2 * (size + marge), 200, size);
	add(inputLine2);
	inputLine2.addActionListener(this);
	inputLine2.setText("resulting Beaufort key");

    }

    public void actionPerformed(ActionEvent event) {

	// SET THE PINS

	for (KeyWheel wheel : m209wheels.getKeyWheels()) {
	    for (Button button : keysButtons.get(wheel)) {
		if (event.getSource() == button) {
		    wheel.getKeyPins().put(Key.charToKey(button.getLabel().charAt(0)), !wheel.getKeyPins().get(Key.charToKey(button.getLabel().charAt(0))));
		    if (wheel.getKeyPins().get(Key.charToKey(button.getLabel().charAt(0)))) {
			button.setBackground(ACTIVE_BG);
		    } else {
			button.setBackground(DEFAULT_BG);
		    }
		}
	    }
	}

	// SET THE LUGS

	for (Bar bar : m209Bars.getBars()) {
	    for (Button button : lugsButtons.get(bar)) {
		if (event.getSource() == button) {
		    if (button.getBackground() == ACTIVE_BG) {
			if (bar.getLug1().getId().equals(button.getLabel())) {
			    bar.setLug1(Lug.Null);
			} else if (bar.getLug2().getId().equals(button.getLabel())) {
			    bar.setLug2(Lug.Null);
			} else {
			    // XXX error
			}
			button.setBackground(DEFAULT_BG);
		    } else if (button.getBackground() == DEFAULT_BG) {
			if (bar.getLug1() == Lug.Null) {
			    bar.setLug1(Lug.StringToLug(button.getLabel()));

			    button.setBackground(ACTIVE_BG);
			} else if (bar.getLug2() == Lug.Null) {
			    bar.setLug2(Lug.StringToLug(button.getLabel()));

			    button.setBackground(ACTIVE_BG);
			} else {
			    // XXX error
			}
		    } else {
			// XXX error

		    }
		}
	    }
	}

	// VISUALISATION OF THE EXTERNAL KEY

	List<Integer> positions = new ArrayList<Integer>();
	for (KeyWheel wheel : m209wheels.getKeyWheels()) {
	    for (Button button : keysButtons.get(wheel)) {
		if(wheel.getPosition().getKey()==button.getLabel().charAt(0)){
		    button.setForeground(ACTIVE_FG);
		    if(button.getBackground()==ACTIVE_BG){
			positions.add(wheel.getId());
		    }
		}else{
		    button.setForeground(DEFAULT_FG);
		}
	    }
	}

	// VISUALISATION OF THE POSITION

	for (Bar bar : m209Bars.getBars()) {
	    for (Button button : lugsButtons.get(bar)) {
		if(button.getBackground()== ACTIVE_BG && positions.contains(Integer.decode(button.getLabel()))){
		    button.setForeground(ACTIVE_FG);
		}else{
		    button.setForeground(DEFAULT_FG);
		}
	    }
	}
	
	// SET THE EXTERNAL KEY

	String externalKey = inputLine.getText();
	char[] charArray = externalKey.toCharArray();
	for (int i = 0; i < 6; i++) {
	    m209wheels.getKeyWheels().get(i).setInitialPosition(Key.charToKey(charArray[i]));
	}

	// COMPUTATION

	String sResult = new StringBuilder().append(GetBeaufortKey.getResultingInt(m209Bars, m209wheels)).toString();
	inputLine2.setText(sResult);
    }

}
